home *** CD-ROM | disk | FTP | other *** search
- /*
- * Copyright 1992 Eric R. Smith. All rights reserved.
- * Redistribution is permitted only if the distribution
- * is not for profit, and only if all documentation
- * (including, in particular, the file "copying")
- * is included in the distribution in unmodified form.
- * THIS PROGRAM COMES WITH ABSOLUTELY NO WARRANTY, NOT
- * EVEN THE IMPLIED WARRANTIES OF MERCHANTIBILITY OR
- * FITNESS FOR A PARTICULAR PURPOSE. USE AT YOUR OWN
- * RISK.
- */
- #include "xgem.h"
- #include <osbind.h>
- #include <mintbind.h>
- #include <fcntl.h>
- #include <signal.h>
- #include <string.h>
- #include <unistd.h>
- #include <stdlib.h>
- #include <time.h>
- #include "toswin.h"
- #include "twdefs.h"
- #include "twproto.h"
-
- #define FLASHTIME 30
-
- /* external flag: set to indicate the flag for opening a
- * "global" file (if we need to) when we're starting up
- */
- extern int global_flag;
-
- /* file descriptors that have kids attached to them */
- long fd_mask = 0L;
-
- /* file descriptor of TOSRUN */
- extern int trun_fd;
-
- static void write_win __PROTO((TEXTWIN *, char *, int));
-
- /*
- * get a file name using the file selector.
- * "title" is the file selector box title
- * "path" is where to look for the file;
- * "default_name" is a default name for the file;
- * the final name selected is returned in "name"
- */
-
- int
- getfilename(title, name, path, default_name)
- char *title;
- char *name;
- char *path, *default_name;
- {
- extern char *rindex();
- char *s;
- int fresult, fbutton;
- extern int gl_ap_version;
-
- if (path[0] == 0) {
- path[0] = Dgetdrv() + 'A';
- path[1] = ':';
- (void)Dgetpath(&path[2], 0);
- strcat(path, "\\");
- }
- for (s = path; *s; s++) {
- if (*s == '*') goto nowildcard;
- }
- strcpy(s, "*.*");
-
- nowildcard:
- if (gl_ap_version >= 0x140)
- fresult = fsel_exinput(path, default_name, &fbutton, title);
- else
- fresult = fsel_input(path, default_name, &fbutton);
- if (fresult <= 0 || fbutton != 1 || !default_name[0])
- return FAIL;
- s = rindex(path, '\\');
- if (!s)
- s = &path[2];
- else
- s++;
- *s = 0;
- strcpy(name, path);
- strcat(name, default_name);
- return OK;
- }
-
- /*
- * if the program named by "fname" is a .TTP one, prompt the
- * user for arguments and copy them into "argstr"; otherwise
- * copy in a null command line. Return FAIL if the user
- * cancelled the request.
- */
-
- int
- getargs(fname, argstr)
- char *fname, *argstr;
- {
- char *lastdot = 0;
- int i, x, y, w, h;
- TEDINFO *ted;
- OBJECT *argdial;
- char *inp;
-
- *argstr = 0;
- while (*fname) {
- if (*fname == '.')
- lastdot = fname;
- else if (*fname == '\\')
- lastdot = 0;
- fname++;
- }
- if (lastdot && !strcmp(lastdot, ".TTP")) {
- rsrc_gaddr(0, ARGDIAL, &argdial);
- ted = (TEDINFO *)argdial[ARGSTR].ob_spec;
- inp = (char *)ted->te_ptext;
- *inp = 0;
- form_center(argdial, &x, &y, &w, &h);
- wind_update(1);
- form_dial(FMD_START, 0, 0, 32, 32, x, y, w, h);
- if (win_flourishes)
- form_dial(FMD_GROW, 0, 0, 32, 32, x, y, w, h);
-
- objc_draw(argdial, 0, 2, x, y, w, h);
-
- i = form_do(argdial, ARGSTR);
-
- if (win_flourishes)
- form_dial(FMD_SHRINK, 0, 0, 32, 32, x, y, w, h);
-
- form_dial(FMD_FINISH, 0, 0, 32, 32, x, y, w, h);
- objc_change(argdial, i, 0, x, y, w, h, NORMAL, 0);
- wind_update(0);
- if (i == ARGCAN) return FAIL;
- strcpy(argstr, inp);
- }
- return OK;
- }
-
- char progpath[128];
- char dfltprog[128];
-
- int
- getprogname(name)
- char *name;
- {
- return getfilename(Strng(EXECPRG), name, progpath, dfltprog);
- }
-
- /*
- * typeit: type the user's input into a window. Note that this routine is
- * called when doing a 'paste' operation, so we must watch out for possible
- * deadlock conditions
- */
-
- #define READBUFSIZ 256
- static char buf[READBUFSIZ];
-
- int
- typeit(w, code, shift)
- WINDOW *w;
- int code, shift;
- {
- TEXTWIN *t = w->extra;
- long offset, height;
- long c = (code & 0x00ff) | (((long)code & 0x0000ff00) << 8L) |
- ((long)shift << 24L);
- long r;
- if (t->miny) {
- offset = t->miny * t->cheight;
- if (offset > t->offy) {
- /* we were looking at scroll back */
- /* now move so the cursor is visible */
- height = t->cheight * t->maxy - w->wi_h;
- if (height <= 0)
- offset = 0;
- else {
- offset = 1000L * t->cy * t->cheight/height;
- if (offset > 1000L) offset = 1000L;
- }
- (*w->vslid)(w, offset);
- }
- }
-
- if (t->fd) {
- r = Foutstat(t->fd);
- if (r <= 0) {
- r = Fread(t->fd, (long)READBUFSIZ, buf);
- if (r > 0) {
- write_win(t, buf, (int)r);
- }
- (void)Fselect(500,0L,0L,0L);
- r = Foutstat(t->fd);
- }
- if (r > 0) {
- (void)Fputchar(t->fd, c, 0);
- return 1;
- }
- }
- return 0;
- }
-
- void (*oldtopped)(), (*oldclosed)();
-
- extern MENU *sysbar;
- extern int appl_menus, sys_menu;
-
- void
- top_menu(v, f)
- WINDOW *v;
- void (*f)();
- {
- ENTRY *e;
- TEXTWIN *t = v->extra;
- TEXTWIN *oldt;
- int enable = (v->wtype == TEXT_WIN);
-
- if (gl_topwin && gl_topwin->wtype == TEXT_WIN &&
- gl_topwin->extra != t)
- oldt = gl_topwin->extra;
- else
- oldt = 0;
-
- for (e = windowmenu->contents; e; e = e->next) {
- if (e->entry[0] != '-')
- if (enable)
- enable_entry(windowmenu, e);
- else
- disable_entry(windowmenu, e);
- }
- for (e = gadgmenu->contents; e; e = e->next) {
- if (e->entry[0] != '-')
- if (enable)
- enable_entry(gadgmenu, e);
- else
- disable_entry(gadgmenu, e);
- }
-
- enable_entry(filemenu, closeentry);
-
- #ifdef GLOBL_APPL_MENUS
- if (v->menu && appl_menus) {
- show_menu(v->menu);
- sys_menu = 0;
- } else if (!sys_menu) {
- show_menu(sysbar);
- sys_menu = 1;
- }
- #endif
- if (enable)
- curs_off(t);
- if (oldt) {
- /* change the cursor states, maybe */
- curs_off(oldt);
- }
- (*f)(v);
- focuswin = gl_topwin;
- if (enable) {
- curs_on(t);
- refresh_textwin(t);
- }
- if (oldt) {
- curs_on(oldt);
- refresh_textwin(oldt);
- }
- }
-
- static void
- top_text(v)
- WINDOW *v;
- {
- top_menu(v, oldtopped);
- }
-
- static void
- desk_menu(v)
- WINDOW *v;
- {
- ENTRY *e;
-
- (*oldclosed)(v);
- if (v->menu)
- unloadmenu(v->menu);
- if (!gl_topwin) {
- for (e = windowmenu->contents; e; e = e->next) {
- if (e->entry[0] != '-')
- disable_entry(windowmenu, e);
- }
- for (e = gadgmenu->contents; e; e = e->next) {
- if (e->entry[0] != '-')
- disable_entry(gadgmenu, e);
- }
- disable_entry(filemenu, closeentry);
- #ifdef GLOBAL_APPL_MENUS
- if (!sys_menu) {
- show_menu(sysbar);
- sys_menu = 1;
- }
- #endif
- }
- }
-
- /*
- * set up a new text window with a process running in it
- * "progname" is the program's name;
- * "progargs" are the arguments for it;
- * "progdir" is the directory to change to;
- * "x" and "y" give where the window is to be opened
- * "rows" and "cols" are the number of rows and columns for it,
- * respectively;
- * "scroll" are the number of lines of scrollback to be
- * alloted for the window
- *
- * NOTE: the window is *not* actually opened here; it's the
- * caller's responsibility to do that.
- */
-
- TEXTWIN *
- newproc(progname, progargs, progdir, x, y, cols, rows, scroll, kind,
- font, points)
- char *progname, *progargs, *progdir;
- int x, y, cols, rows, kind, scroll, font, points;
- {
- extern void vt52_putch();
- extern long termfunc; /* set in main.c */
- TEXTWIN *t;
- int i, ourfd, kidfd;
- #ifdef OLD_WAY
- long oldblock;
- #else
- long r;
- #endif
- static char termname[64];
- static char argbuf[128];
- struct winsize tw;
- char *p, *arg, c;
- char *newenv = 0;
- int oldfont, oldheight;
-
- /* copy over the args */
- p = argbuf+1;
- arg = progargs;
- for (i = 0; i < 125; i++) {
- c = *arg++;
- if (!c || c == '\r' || c == '\n') break;
- *p++ = c;
- }
- *p = 0;
- argbuf[0] = i;
-
- oldfont = default_font;
- oldheight = default_height;
- default_font = font;
- default_height = points;
- t = create_textwin(progname, x, y, cols, rows, scroll, kind);
- default_font = oldfont;
- default_height = oldheight;
-
- if (!t) {
- form_alert(1, AlertStrng(NOWINS));
- return 0;
- }
- t->output = vt52_putch;
- t->prog = strdup(progname);
- t->cmdlin = strdup(progargs);
- t->progdir = strdup(progdir);
- t->win->menu = loadmenu(progname);
- if (t->win->menu) {
- t->win->infostr = strdup(menustr(t->win->menu));
- } else {
- change_window_gadgets(t->win, t->win->wi_kind & ~INFO);
- }
-
- newenv = envstr(progname, progargs, progdir, cols, rows);
-
- if (newenv && (env_options & E_ARGV)) {
- if (!*argbuf)
- argbuf[1] = 0;
- argbuf[0] = 127; /* mark ARGV arg. passing */
- }
-
- strcpy(termname, "U:\\pipe\\pty.A");
- for (i = 0; i < 20; i++) {
- termname[12] = 'A' + i;
- ourfd = Fcreate(termname, FA_SYSTEM|FA_HIDDEN|global_flag);
- if (ourfd > 0) {
- /* set to non-delay mode, so Fread() won't block */
- (void)Fcntl(ourfd, (long)O_NDELAY, F_SETFL);
- break;
- }
- }
- if (ourfd < 0) {
- form_alert(1, AlertStrng(NOPTY));
- abort_open:
- destroy_textwin(t);
- return 0;
- }
- t->fd = ourfd;
- tw.ws_xpixel = tw.ws_ypixel = 0;
- tw.ws_row = rows;
- tw.ws_col = cols;
-
- (void)Fcntl(ourfd, &tw, TIOCSWINSZ);
- t->win->keyinp = typeit;
- t->win->mouseinp = win_click;
- oldtopped = t->win->topped;
- t->win->topped = top_text;
- oldclosed = t->win->closed;
- t->win->closed = desk_menu;
-
- #ifdef OLD_WAY
- oldblock = Psigblock(1L << SIGCHLD);
- #endif
-
- i = Pvfork();
- if (i < 0) {
- (void)Fclose(ourfd);
- #ifdef OLD_WAY
- (void)Psigsetmask(oldblock);
- #endif
- form_alert(1, AlertStrng(NOPROC));
- goto abort_open;
- } else if (i == 0) {
- if (oldACC)
- (void)Setexc(0x102, termfunc);
- #ifndef OLD_WAY
- i = Pvfork();
- if (i != 0)
- Pterm(i);
- #endif
- (void)Psetpgrp(0, 0);
- kidfd = Fopen(termname, 2);
- if (kidfd < 0) _exit(998);
- (void)Fforce(-1, kidfd);
- (void)Fforce(0, kidfd);
- (void)Fforce(1, kidfd);
- (void)Fforce(2, kidfd);
- (void)Fclose(kidfd);
- (void)chdir(progdir);
- i = Pexec(200, progname, argbuf, newenv);
- _exit(i);
- }
- #ifndef OLD_WAY
- #define WNOHANG 1
- /* reap the exit code of the just terminated process */
- do {
- r = Pwait3(WNOHANG, (void *)0);
- } while (((r & 0xffff0000L) >> 16L) != i);
- i = r & 0x0000ffff;
- #endif
- t->pgrp = i;
- if (!global_flag)
- fd_mask |= (1L << ourfd);
- /* turn on the cursor in the window */
- (*t->output)(t, '\033');
- (*t->output)(t, 'e');
-
- /* and make it flash */
- (*t->output)(t, '\033');
- (*t->output)(t, 't');
- (*t->output)(t, ' '+FLASHTIME);
-
- /* align the window, if necessary */
- if (align_windows)
- t->win->wi_x &= ~7;
-
- #ifdef OLD_WAY
- (void)Psigsetmask(oldblock);
- #endif
- if (newenv) free(newenv);
-
- return t;
- }
-
- /* After this many bytes have been written to a window, it's time to
- * update it. Note that we must also keep a timer and update all windows
- * when the timer expires, or else small writes will never be shown!
- */
- #define THRESHOLD 400
-
- static void
- write_win(t, b, cnt)
- TEXTWIN *t;
- char *b;
- int cnt;
- {
- unsigned char *buf = (unsigned char *)b, c;
- int limit = smoothscroll ? 1 : NROWS(t) - 1;
-
- while (cnt-- > 0) {
- c = *buf++;
- (*t->output)(t, c);
- t->nbytes++;
- if (t->nbytes >= THRESHOLD || t->scrolled >= limit) {
- refresh_textwin(t);
- }
- }
- }
-
- #define EIHNDL -37
-
- static char exit_msg[] = "\r\n<EXITED>\r\n";
-
- static void
- rebuild_fdmask(which)
- long which;
- {
- int i;
- WINDOW *w, *wnext;
- TEXTWIN *t;
-
- for (i = 0; i < 32; i++) {
- if ((which & (1L << i)) && (Finstat(i) < 0)) {
- /* window has died now */
- fd_mask &= ~(1L << i);
- for (w = gl_winlist; w; w = wnext) {
- wnext = w->next;
- if (w->wtype != TEXT_WIN) continue;
- t = w->extra;
- if (t && t->fd == i) {
- if (autoclose)
- (*w->closed)(w);
- else {
- write_win(t, exit_msg,
- (int)strlen(exit_msg));
- refresh_textwin(t);
- (void)Fclose(i);
- t->fd = 0;
- }
- }
- }
- }
- }
- }
-
- void
- exec_tos(buf)
- char *buf;
- {
- TEXTWIN *t;
- char *dir, *name, *args;
-
- dir = buf;
- while (*buf && *buf != ' ') buf++;
- if (*buf) *buf++ = 0;
- name = buf;
- while (*buf && *buf != ' ') buf++;
- if (*buf) *buf++ = 0;
- args = buf;
- t = newproc(name, args, dir, 0, 0, stdcol, stdrow, stdscroll, default_kind,
- default_font, default_height);
- if (_app || opened)
- open_window(t->win);
- }
-
- static long lasthz;
-
- void
- fd_input()
- {
- #define MAX_DELAY 3 /* max no. of 50Hz ticks before a refresh */
- long readfds, r, checkdead;
- int read;
- int workdone = 0;
- WINDOW *w;
- TEXTWIN *t;
- int updtime;
- long newhz;
-
- r = 0;
- checkdead = 0;
-
- newhz = clock();
- updtime = (newhz - lasthz) >> 2;
- lasthz = newhz;
-
- if (fd_mask) {
- readfds = fd_mask;
- if ((r = Fselect(1, &readfds, 0L, 0L)) > 0) {
- if (trun_fd && (readfds & (1L << trun_fd))) {
- read = Finstat(trun_fd);
- if (read > 0)
- read = Fread(trun_fd, (long)READBUFSIZ,
- buf);
- if (read > 0)
- exec_tos(buf);
- }
- for (w = gl_winlist; w; w = w->next) {
- if (w->wtype != TEXT_WIN) continue;
- t = w->extra;
- if (!t || !t->fd) continue;
- if (readfds & (1L << t->fd)) {
- read = Fread(t->fd, (long)READBUFSIZ,
- buf);
- if (read > 0) {
- write_win(t, buf, read);
- } else {
- checkdead |= (1L << t->fd);
- }
- }
- }
- workdone = 1;
- }
- if (checkdead)
- rebuild_fdmask(checkdead);
- }
- if (r == EIHNDL) { /* invalid handle?? */
- rebuild_fdmask(fd_mask);
- }
-
- if (workdone) {
- gl_timer = MultiTOS ? SHORTWAIT : NOMULTIWAIT;
- } else {
- gl_timer = MultiTOS ? LONGWAIT : NOMULTIWAIT;
- }
-
- /* for all windows on screen, see if it's time to refresh them */
- for (w = gl_winlist; w; w = w->next) {
- if (w->wtype != TEXT_WIN) continue;
- t = w->extra;
- /* should we flash the cursor in this window? */
- if (t->flashperiod) {
- t->flashtimer -= updtime;
- if (t->flashtimer <= 0) {
- t->flashtimer = t->flashperiod;
- curs_flash(t);
- t->nbytes++;
- }
- }
- if (!t || !t->fd || !t->nbytes) continue;
- t->draw_time += updtime;
- if (t->draw_time < MAX_DELAY) continue;
- refresh_textwin(t);
- }
- }
-
- /*
- * similar to fd_input, but used only when we're an ACC;
- * this loop doesn't use Fselect, so it's less efficient
- */
-
- void
- acc_input()
- {
- long r, checkdead;
- int read;
- int workdone = 0;
- WINDOW *w;
- TEXTWIN *t;
- int updtime;
- long newhz;
-
- r = 0;
- checkdead = 0;
-
- newhz = clock();
- updtime = (newhz - lasthz) >> 2;
- lasthz = newhz;
-
- read = Finstat(trun_fd);
- if (read > 0) {
- read = Fread(trun_fd, (long)READBUFSIZ, buf);
- if (read > 0)
- exec_tos(buf);
- }
- for (w = gl_winlist; w; w = w->next) {
- if (w->wtype != TEXT_WIN) continue;
- t = w->extra;
- if (!t || !t->fd) continue;
- if ((r = Finstat(t->fd)) != 0) {
- read = Fread(t->fd, (long)READBUFSIZ, buf);
- if (read > 0) {
- write_win(t, buf, read);
- } else if (r < 0) {
- if (autoclose) {
- (*w->closed)(w);
- } else {
- write_win(t, exit_msg,
- (int)strlen(exit_msg));
- refresh_textwin(t);
- (void)Fclose(t->fd);
- t->fd = 0;
- }
- }
- workdone = 1;
- }
- }
-
- if (workdone) {
- gl_timer = MultiTOS ? SHORTWAIT : NOMULTIWAIT;
- } else {
- gl_timer = MultiTOS ? LONGWAIT : NOMULTIWAIT;
- }
-
- /* for all windows on screen, see if it's time to refresh them */
- for (w = gl_winlist; w; w = w->next) {
- if (w->wtype != TEXT_WIN) continue;
- if (w->wi_handle < 0) continue;
- t = w->extra;
- /* should we flash the cursor in this window? */
- if (t->flashperiod) {
- t->flashtimer -= updtime;
- if (t->flashtimer <= 0) {
- t->flashtimer = t->flashperiod;
- curs_flash(t);
- t->nbytes++;
- }
- }
- if (!t || !t->fd || !t->nbytes) continue;
- t->draw_time += updtime;
- if (t->draw_time < MAX_DELAY) continue;
- refresh_textwin(t);
- }
- }
-
- /*
- * send an untranslated character to the top window
- */
-
- void
- send_char()
- {
- WINDOW *v;
- OBJECT *quote_dial;
- int event, mshift, keycode, dummy;
- int x, y, w, h;
-
- v = gl_topwin;
- if (v && v->wtype == TEXT_WIN) {
- event = evnt_multi(MU_KEYBD|MU_TIMER,
- 0, 0, 0,
- 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0,
- NULL,
- 1200L, /* wait 1.2 seconds */
- &dummy, &dummy, &dummy, &mshift,
- &keycode, &dummy);
- if (event & MU_KEYBD) {
- (*v->keyinp)(v, keycode, mshift);
- } else {
- rsrc_gaddr(0, QUOTEIT, "e_dial);
- form_center(quote_dial, &x, &y, &w, &h);
- wind_update(BEG_MCTRL);
- form_dial(FMD_START, 0, 0, 32, 32, x, y, w, h);
- if (win_flourishes)
- form_dial(FMD_GROW, 0, 0, 32, 32, x, y, w, h);
-
- objc_draw(quote_dial, 0, 2, x, y, w, h);
- event = evnt_multi(MU_KEYBD|MU_BUTTON,
- 0x0101, 0x0003, 0,
- 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0,
- NULL,
- 0L,
- &dummy, &dummy, &dummy, &mshift,
- &keycode, &dummy);
-
- if (win_flourishes)
- form_dial(FMD_SHRINK, 0, 0, 32, 32, x, y, w, h);
- form_dial(FMD_FINISH, 0, 0, 32, 32, x, y, w, h);
- wind_update(END_MCTRL);
- if (event & MU_KEYBD) {
- (*v->keyinp)(v, keycode, mshift);
- }
- }
- }
-
- }
-